﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SharpGL.SceneGraph;
using SharpGL;
using ProjetoKinect.Model;
using ProjetoKinect.Model3d;
using ProjetoKinect.openGL;
using SharpGL.Serialization;
using SharpGL.SceneGraph.Core;
using Microsoft.Kinect;
using ProjetoKinect.enums;
using ProjetoKinect;

namespace HiSharpGL
{

    public partial class OpenGLWindow : Window
    {
        private static double INITIAL_X = 0;
        private static double INITIAL_Y = 0;
        private static double INITIAL_Z = 60;

        // rotation angle increment 
        public static int ANGLE_COUNTER = 5;

        private MyOpenGL myOpenGL;
        private ParseObj parseObj;
        private List<TriangleObject> ascTriangleObjectList;
        private List<TriangleObject> decTriangleObjectList;
        private List<SharpGL.SceneGraph.Primitives.Polygon> polygons = new List<SharpGL.SceneGraph.Primitives.Polygon>();

        private float scale = 1.0f;
        private float angleY = 0.0f;
        private float angleX = 0.0f;

        private KinectController kinectController;
        private Boolean hasRemoved = false;
        private BodyControl bodyControl = new BodyControl();

        MyPoint3D cameraPosition = new MyPoint3D(INITIAL_X, INITIAL_Y, INITIAL_Z);

        public OpenGLWindow()
        {
            InitializeComponent();
            myOpenGL = new MyOpenGL(ANGLE_COUNTER);

            parseObj = new ParseObj(@"C:\Imagens\obj\3em1cuboOk.obj");
            ascTriangleObjectList = parseObj.getTriangleObjects(Colors.Black);

            parseObj = new ParseObj(@"C:\Imagens\obj\3em1ossoOk.obj");
            ascTriangleObjectList.AddRange(parseObj.getTriangleObjects(Colors.Yellow));

            parseObj = new ParseObj(@"C:\Imagens\obj\3em1peleOk.obj");
            ascTriangleObjectList.AddRange(parseObj.getTriangleObjects(Colors.Blue));

            decTriangleObjectList = new List<TriangleObject>(ascTriangleObjectList);

            foreach (TriangleObject triangleObject in ascTriangleObjectList)
            {
                triangleObject.getTriangleList().Sort(new MyTriangleDecComparer());
            }

            WindowState = WindowState.Maximized;

        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {

            kinectController = new KinectController();
            kinectController.findKinectSensor();
            kinectController.enableSkeletonStream(this.SensorSkeletonFrameReady);
           
            OpenGL gl = openGLControl.OpenGL;
            myOpenGL.initialized(gl);
            openGLControl.OpenGLDraw += openGLControl_OpenGLDraw;
            openGLControl.OpenGLDraw -= openGLControl_OpenGLDraw;

        }

        private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {

            if (!hasRemoved)
            {
                Skeleton[] skeletons = kinectController.getSkeletons(e);
                foreach (Skeleton skel in skeletons)
                {
                    if (skel.TrackingState == SkeletonTrackingState.Tracked)
                    {
                        controlImage(skel);
                    }
                }
            }
        }

        private void controlImage(Skeleton skeleton)
        {
            selectedFunction.Text = "_";
            bodyControl.setSkeletonJoints(skeleton);

            MyJoint leftHandMyJoint = bodyControl.getMyJointByJointType(JointType.HandLeft);
            MyJoint rightHandMyJoint = bodyControl.getMyJointByJointType(JointType.HandRight);

            zoomWithGesture(bodyControl);
            rotateWithGesture(bodyControl);

            goToConfigurationScreen();
            exitWithGesture();

            openGLControl.OpenGLDraw += openGLControl_OpenGLDraw;
            openGLControl.OpenGLDraw -= openGLControl_OpenGLDraw;

           
        }

        private void goToConfigurationScreen()
        {
            if (bodyControl.isTwoHandsFrontPosition())
            {
                Console.Beep();
                /*if (!hasRemoved)
                {
                    this.kinectController.stopFullSensor();
                    new ActivitySelector().Show();
                    this.Close();
                    hasRemoved = true;
                }*/
            }
        }

        private void exitWithGesture()
        {
            if (bodyControl.isSurrenderPosition())
            {
                if (!hasRemoved)
                {
                    hasRemoved = true;
                    openGLControl.OpenGLDraw -= openGLControl_OpenGLDraw;
                    this.kinectController.stopFullSensor();
                    new ActivitySelector().Show();
                    this.Close();
                }
            }
        }

        private void zoomWithGesture(BodyControl bodyControl)
        {
            float zoomCounter = 0.01f;

            //zoom left hand upside
            if (bodyControl.getLeftHandLocation().Equals(HandLocation.LU))
            {
                selectedFunction.Text = "Zoom";
                if (bodyControl.getJointMovimentStatus(JointType.HandRight, Axis.AXIS_Z).Equals(MovimentStatus.DECREASING))
                {
                    scale -= zoomCounter;
                }
                else if (bodyControl.getJointMovimentStatus(JointType.HandRight, Axis.AXIS_Z).Equals(MovimentStatus.INCREASING))
                {
                    scale += zoomCounter;
                }
            }
        }
        private void rotateWithGesture(BodyControl bodyControl)
        {

            if (bodyControl.getLeftHandLocation().Equals(HandLocation.LD))
            {
                selectedFunction.Text = "Rotação Y";
                if (bodyControl.isJoinDistantFromJointBase(JointType.HandRight, JointType.HipRight))
                {

                    if (bodyControl.getJointMovimentStatus(JointType.HandRight, Axis.AXIS_X, 3).Equals(MovimentStatus.DECREASING))
                    {
                        angleY += ANGLE_COUNTER;
                    }
                    else if (bodyControl.getJointMovimentStatus(JointType.HandRight, Axis.AXIS_X, 3).Equals(MovimentStatus.INCREASING))
                    {
                        angleY -= ANGLE_COUNTER;
                    }

                }
            }
            else if (bodyControl.getLeftHandLocation().Equals(HandLocation.LM))
            {
                selectedFunction.Text = "Rotação X";
                if (bodyControl.isJoinDistantFromJointBase(JointType.HandRight, JointType.HipRight))
                {
                    if (bodyControl.getJointMovimentStatus(JointType.HandRight, Axis.AXIS_X, 3).Equals(MovimentStatus.DECREASING))
                    {
                        angleX += ANGLE_COUNTER;
                    }
                    else if (bodyControl.getJointMovimentStatus(JointType.HandRight, Axis.AXIS_X, 3).Equals(MovimentStatus.INCREASING))
                    {
                        angleX -= ANGLE_COUNTER;
                    }

                }
            }

        }

        private void openGLControl_OpenGLDraw(object sender, OpenGLEventArgs args)
        {
            OpenGL gl = openGLControl.OpenGL;

            //  Clear the color and depth buffer.
            gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);

            //  Load the identity matrix.
            gl.LoadIdentity();

            gl.Rotate(angleY, 0.0f, 1.0f, 0.0f);
            gl.Rotate(angleX, 1.0f, 0.0f, 0.0f);

            gl.Scale(scale, scale, scale);
            cameraPosition.setAll(INITIAL_X, INITIAL_Y, INITIAL_Z);

            cameraPosition.rotateClockWiseY(angleY);
            cameraPosition.rotateClockWiseX(angleX);
            if (angleY > 360)
            {
                angleY = angleY - 360;
            }
            myOpenGL.drawnTriangleObjectList(gl, decTriangleObjectList, cameraPosition);

            this.selectedFunction.Text = angleY + "";
            // Nudge the rotation.
            angleY += 5.0f;
            // angleX += 5.0f;
            // scale += 0.1f;
        }

        private void openGLControl_OpenGLInitialized(object sender, OpenGLEventArgs args)
        {
            OpenGL gl = openGLControl.OpenGL;
            myOpenGL.initialized(gl);
        }

        private void openGLControl_Resized(object sender, OpenGLEventArgs args)
        {
            OpenGL gl = openGLControl.OpenGL;
            myOpenGL.resized(gl, cameraPosition, Width, Height);
        }


    }
}
